package cn.dagteam.springboot.mongodb.starter.listener;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.AfterDeleteEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeDeleteEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldFilter;

import cn.dagteam.springboot.mongodb.starter.Cascade;

@Component
public class CascadeMongoEventListener extends AbstractMongoEventListener<Object> {

	@Autowired
	private MongoTemplate mongoTemplate;

	@Override
	public void onBeforeConvert(BeforeConvertEvent<Object> event) {
		ReflectionUtils.doWithFields(event.getSource().getClass(), new CascadeSaveCallback(event.getSource(), mongoTemplate), CASCADE_FIELDS);
		super.onBeforeConvert(event);
	}

	@Override
	public void onBeforeSave(BeforeSaveEvent<Object> event) {
		super.onBeforeSave(event);
	}
	
	@Override
	public void onAfterSave(AfterSaveEvent<Object> event) {
		ReflectionUtils.doWithFields(event.getSource().getClass(), new CascadeSaveLinkCallback(event.getSource(), mongoTemplate), CASCADE_FIELDS);
		super.onAfterSave(event);
	}

	@Override
	public void onBeforeDelete(BeforeDeleteEvent<Object> event) {
		ReflectionUtils.doWithFields(event.getType(), new CascadeDeleteCallback(event, mongoTemplate), CASCADE_FIELDS);
		super.onBeforeDelete(event);
	}

	@Override
	public void onAfterDelete(AfterDeleteEvent<Object> event) {
		super.onAfterDelete(event);
	}
	
	public static final FieldFilter CASCADE_FIELDS = field -> field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(Cascade.class);
}
